/**
 * 
 */
package info.niwota.group;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Properties;

import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;

/**
 * @author qiangli
 * 
 */
public final class Email {
	private static final Properties props = new java.util.Properties();

	private static final String PROTO_SMTP = "smtp";

	private static final String TYPE_TEXT_HTML = "text/html";
	
	private static final String TYPE_TEXT_PLAIN = "text/plain";

	public static final String EMAIL_SEPARATOR = ",";

	static {
		//
		MailcapCommandMap mc = (MailcapCommandMap)CommandMap.getDefaultCommandMap();
		mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
		mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
		mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
		mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
		mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
		CommandMap.setDefaultCommandMap(mc);
		//
		java.security.Security.addProvider(new x.org.apache.harmony.xnet.provider.jsse.JSSEProvider()); 
		//
		props.put("mail.transport.protocol", PROTO_SMTP);
		props.put("mail.smtp.auth", "true");
		//
		props.put("mail.debug", Constants.MAIL_DEBUG);
	}

	private static class MyFileDataSource extends FileDataSource {
		private String mimeType;
		public MyFileDataSource(File file, String mimeType) {
			super(file);
			this.mimeType = mimeType;
		}
		@Override
		public String getContentType() {
			String t = (mimeType == null ? super.getContentType() : mimeType);
			return t;
		}
	}

	private static Session getSession() {
		Session session = Session.getDefaultInstance(props);
		//session.setDebug(true); //TODO COMMENT OUT for production release
		return session;
	}

	public static void mail(Context context, String id, String to, String subject,
			String body) throws Exception {
		props.putAll(Preferences.getPreferences(context));
		//
		String nickname = props.getProperty(Preferences.NICKNAME, null);
		String from = props.getProperty(Preferences.EMAIL);
		String replyto = props.getProperty(Preferences.REPLYTO);
		if (TextUtils.isEmpty(replyto)) {
			replyto = from;
		}
		mail(context, id, nickname, from, replyto, to, subject, body, TYPE_TEXT_HTML);
	}

	private static void mail(Context context, String id, String nickname, String from, String replyto, String to,
			String subject, String body, String type) throws Exception {
		Session sess = getSession();
		//
		Message msg = createMessage(context, sess, id, nickname, from, replyto, to, subject);
		//
		msg.setContent(body, type);
		//
		send(sess, msg);
	}

	private static Message createMessage(Context context, Session sess, String id, String nickname,
			String from, String replyto, String to, String subject)
			throws AddressException, MessagingException {
		Message msg = new MimeMessage(sess);
		msg.setFrom(toAddress(nickname, from));
		msg.setReplyTo(new Address[] { toAddress(nickname, replyto) });
		//
		msg.setRecipients(javax.mail.Message.RecipientType.TO, InternetAddress
				.parse(to));
		msg.setSubject(subject);
		//
		msg.setHeader("X-Mailer", context.getString(R.string.app_xmailer));
		String cid = from+"/"+id;
		msg.setHeader("X-Channel-ID", cid);
		//
		return msg;
	}

	private static Address toAddress(String nickname, String from) throws AddressException {
		Address sender = null;
		try {
			sender = (TextUtils.isEmpty(nickname) ? 
					new InternetAddress(from) :  new InternetAddress(from, nickname, "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			sender = new InternetAddress(from);
		}
		return sender;
	}

	public static void send(Context context, String id, String to, String subject,
			String body, File talk, File attach) throws Exception {
		props.putAll(Preferences.getPreferences(context));
		//
		String nickname = props.getProperty(Preferences.NICKNAME, null);
		String from = props.getProperty(Preferences.EMAIL);
		String replyto = props.getProperty(Preferences.REPLYTO);
		if (TextUtils.isEmpty(replyto)) {
			replyto = from;
		}
		send(context, id, nickname, from, replyto, to, subject, body, talk, attach, TYPE_TEXT_HTML);
	}

	private static void send(Context ctx, String id, String nickname, String from, String replyto, String to,
			String subject, String body, File talk, File attach, String type) throws Exception {
		Session sess = getSession();
		//
		Message msg = createMessage(ctx, sess, id, nickname, from, replyto, to, subject);
		//
		Multipart mp = new MimeMultipart();

		BodyPart bp = new MimeBodyPart();
		bp.setContent(body, type);
		mp.addBodyPart(bp);
		//
		//ensure audio file name and type
		String sender = Preferences.getSender(ctx);
		String fname = (TextUtils.isEmpty(sender) == false ? ctx.getString(R.string.email_attach_filename, sender) : "voice-message"); //sender should never be null
		String n = (talk == null ? null : talk.getName());
		String ftype = null;
		String fext = null;
		if (n == null) {
			ftype = FileFormats.AUDIO_ANY;
			fext = "";
		} else if (n.endsWith(FileFormats.EXT_WAV)) {
			ftype = FileFormats.AUDIO_WAV;
			fext = FileFormats.EXT_WAV;
		} else {
			ftype = FileFormats.AUDIO_3GPP;
			fext = FileFormats.EXT_3GPP;
		}
		attachFile(mp, talk, ftype, (fname + fext), MimeBodyPart.ATTACHMENT); //optional for web link/page
		//
		attachFile(mp, attach, null, null, MimeBodyPart.ATTACHMENT); //optional
		//
		msg.setContent(mp);
		//
		send(sess, msg);
	}

	private static void attachFile(Multipart mp, File f, String type, String name, String disposition) throws Exception {
		if (f == null || !f.exists()) {
			return;
		}
		MimeBodyPart bp = new MimeBodyPart();
		if (type == null) {
			type = Files.guessType(f.getName());
		}
		DataSource ds = new MyFileDataSource(f, type);
		bp.setDataHandler(new DataHandler(ds));
		if (name == null) {
			name = f.getName();
		}
		bp.setFileName(name);
		bp.setDisposition(disposition);
		//
		mp.addBodyPart(bp);
	}
	
	private static void send(Session sess, Message msg) throws Exception {
		String usr = props.getProperty(Preferences.USERNAME);
		String pwd = props.getProperty(Preferences.PASSWORD);
		//
		Transport tr = sess.getTransport(PROTO_SMTP);
		tr.connect(usr, pwd);
		msg.saveChanges();
		tr.sendMessage(msg, msg.getAllRecipients());
		tr.close();
		//
	}

	public static void test(Context context) throws Exception {
		props.putAll(Preferences.getPreferences(context));
		String nickname = props.getProperty(Preferences.NICKNAME, null);
		String from = props.getProperty(Preferences.EMAIL);
		Resources res = context.getResources();
		String subj = res.getString(R.string.test_email_subject);
		String sig = Preferences.getSignature(context);
		String body = res.getString(R.string.test_email_body, sig);
		String id = "-1";
		//
		mail(context, id ,nickname, from, from, from, subj, body, TYPE_TEXT_PLAIN);
	}

	private Email() {
	}
}
